import React from 'react'
import style from './style'
import ReactDOM from 'react-dom'
import matches from 'component-matches-selector'
import indexof from 'indexof-element'

export default (options={}) => ComposedComponent => class extends React.Component {

	state = {
		from: null,
		to: null,
		dragEnd: false
	}

	componentDidMount() {
		this.el = ReactDOM.findDOMNode(this)
		this.els = this.el.children
		this.el.addEventListener('mousedown', this.mouseDown.bind(this))
		this.el.addEventListener('dragstart', this.dragStart.bind(this))
		this.el.addEventListener('dragover', this.dragOver.bind(this))
		this.el.addEventListener('dragenter', this.dragOver.bind(this))
		this.el.addEventListener('dragend', this.dragEnd.bind(this))
		this.el.addEventListener('drop', this.drop.bind(this))
		this.clone = this.el.children[0].cloneNode(false);
		// reset
		this.clone.setAttribute('data-reactid', new Date().getTime())
		this.clone.classList.add('sortable-placeholder')
		this.ignored = options.ignored
	}

	mouseDown(e) {
		if (!this._handle) return;
		this.match = matches(e.target, this._handle);
	}

	drop(e) {
		e.stopPropagation();
		this.dragEnd(e);
		this.reset();
	}

	reset() {
		this.draggable = null;
		this.display = null;
		this.i = null;
	}

	dragEnd(e) {
		e.stopPropagation()
		if (!this.draggable) return;
		let to = indexof(this.clone)
		const from = this.i
		if (from < to) {
			to = to-1
		}
		if (this.clone) remove(this.clone);
		this.draggable.style.display = this.display;

		if (from === to) return;
		this.setState({
			dragEnd: true,
			from,
			to
		})
	}

	dragOver(e) {
		var el = e.target
				, next
				, ci
				, i;

		e.preventDefault();
		e.stopPropagation()
		if (!this.draggable || el == this.el) return;
		e.dataTransfer.dropEffect = 'move';
		this.draggable.style.display = 'none';

		// parent
		while (el.parentElement != this.el) el = el.parentElement;
		next = el;
		ci = indexof(this.clone);
		i = indexof(el);
		if (ci < i) next = el.nextElementSibling;
		if (this.ignored && matches(el, this.ignored)) return;
		this.el.insertBefore(this.clone, next);
	}

	dragStart(e) {
		e.target.classList.remove(options.enter)
		e.stopPropagation()
		if (this.ignored && matches(e.target, this.ignored)) return e.preventDefault();
		if (this._handle && !this.match) return e.preventDefault();
		this.draggable = e.target;
		const { width, height } = this.draggable.getBoundingClientRect()
		this.clone.style.width = width + 'px'
		this.clone.style.height = height + 'px'
		while (this.draggable.parentNode != this.el) {                                                                                                            
			this.draggable = this.draggable.parentNode;                                                                                                             
		}
		this.display = window.getComputedStyle(e.target).display;
		this.i = indexof(e.target);
		e.dataTransfer.setData('text', ' ');
		e.dataTransfer.effectAllowed = 'move';
		this.setState({
			dragEnd:false
		})
	}

	render() {
		return (
			<ComposedComponent {...this.state} {...this.props}/>
		)
	}
}

function remove(el){
	if (!el.parentNode) return;
	el.parentNode.removeChild(el);
}
